﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotNetCore.CAP;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using User.API.Data;
using User.API.Data.IntegratedEvents.Events;
using User.API.Filters;

namespace User.API.Controllers
{
    [Produces("application/json")]
    [Route("api/Users/[action]")]
    public class UsersController : BaseController
    {
        private readonly ApplicationDbContext _ctx;
        private readonly ILogger<UsersController> _logger;
        private readonly ICapPublisher _capPulisher;
        public UsersController(ApplicationDbContext ctx, ILogger<UsersController> logger,
            ICapPublisher capPulisher)
        {
            _ctx = ctx;
            _logger = logger;
            _capPulisher = capPulisher;
        }
        [HttpGet]
        public async Task<IActionResult> Get()
        {
            var user = await _ctx.AppUser
                   .AsNoTracking()
                   .Include(t => t.Properties)
                   .FirstOrDefaultAsync(u => u.Id == UserIdentity.UserId);
            if (user == null)
            {
                throw new UserOperationException("User Not exist.");
            }
            return Json(user);
        }
        [HttpPatch]
        public async Task<IActionResult> Patch([FromBody]JsonPatchDocument doc)
        {
            var user = await _ctx.AppUser
                   .Include(t => t.Properties)
                   .FirstOrDefaultAsync(u => u.Id == UserIdentity.UserId);
            if (user == null)
            {
                throw new UserOperationException("User Not exist.");
            }
            //_ctx.RemoveRange(user.Properties);
            //await _ctx.SaveChangesAsync();
            doc.ApplyTo(user);

            using (var trans = _ctx.Database.BeginTransaction())
            {
                await _capPulisher.PublishAsync("finbook.users.patch",new UserprofileChangedEvent() { UserId=user.Id, UserName=user.Name });
                _ctx.Update(user);
                await _ctx.SaveChangesAsync();

                trans.Commit();
            }


            //var originalProps =user.Properties;
            //doc.ApplyTo(user);
            //var newProps = originalProps.Union(user.Properties);

            return Json(user);
        }

        [HttpPost]
        public async Task<IActionResult> CheckOrCreatePhone(string phone)
        {
            var user = await _ctx.AppUser.SingleOrDefaultAsync(u => u.Phone == phone);
            if (user == null)
            {
                await _ctx.AddAsync(new AppUser() { Phone = phone });
                await _ctx.SaveChangesAsync();
            }
            return Ok(new { user.Id, user.Name, user.Company, user.Title, user.Avatar });
        }

        [HttpGet]
        public async Task<IActionResult> GetUserTags()
        {
            var tags = await _ctx.UserTag.AsNoTracking().ToListAsync();
            return Json(tags);
        }
        [HttpGet]
        public async Task<IActionResult> Search(string phone)
        {
            var user = await _ctx.AppUser.AsNoTracking().Include(u => u.Tags).FirstOrDefaultAsync(u => u.Phone.Equals(phone));
            return Json(user);
        }
        [HttpPost]
        public async Task<IActionResult> UpdateUserTags([FromBody]List<string> tags)
        {
            var originalTags = _ctx.AppUser.AsNoTracking().Include(u => u.Tags).First(u => u.Id == UserIdentity.UserId)?.Tags.Select(u => u.Tag).ToList();
            var newTags = tags.Except(originalTags);

            await _ctx.UserTag.AddRangeAsync(newTags.Select(t => new UserTag() { AppUserId = UserIdentity.UserId, CreateTime = DateTime.Now, Tag = t }));
            await _ctx.SaveChangesAsync();
            return Ok();
        }
        [HttpGet]
        public async Task<IActionResult> GetUserInfoAsync(int id)
        {
            return Ok(await _ctx.AppUser.FirstOrDefaultAsync(u => u.Id == id));
        }
    }

}